home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / quicktime / basics / inside mac movie tb code / mtb.c < prev    next >
Encoding:
Text File  |  2000-06-23  |  19.7 KB  |  861 lines

  1. /*
  2.     File:        mtb.c
  3.  
  4.     Contains:    
  5.  
  6.     Written by:     
  7.  
  8.     Copyright:    Copyright © 1992-1999 by Apple Computer, Inc., All Rights Reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.                 8/16/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  20.                 12/4/94        khs                changed the format of the file to the new look and feel
  21.  
  22. */
  23.  
  24.  
  25. // INCLUDES
  26. #include "mtb.h"
  27. #include <TextUtils.h>
  28.  
  29. // FUNCTIONS
  30. void CheckError(OSErr error,
  31.                 Str255 displayString)
  32. {
  33.     if (error == noErr)
  34.         return;
  35.     if (displayString[0] > 0)
  36.         DebugStr(displayString);
  37.     ExitToShell();
  38. }
  39. void DrawFrame(const Rect* trackFrame,
  40.                long curSample)
  41. {
  42.     Str255 numStr;
  43.  
  44.     ForeColor(redColor);
  45.     PaintRect(trackFrame);
  46.  
  47.     ForeColor(blueColor);
  48.     NumToString(curSample, numStr);
  49.     MoveTo(trackFrame->right / 2, trackFrame->bottom / 2);
  50.     TextSize(trackFrame->bottom / 3);
  51.     DrawString(numStr);
  52. }
  53. void AddVideoSamplesToMedia(Media theMedia,
  54.                             const Rect* trackFrame)
  55. {
  56.     long maxCompressedSize;
  57.     GWorldPtr theGWorld = nil;
  58.     long curSample;
  59.     Handle compressedData = nil;
  60.     Ptr compressedDataPtr;
  61.     ImageDescriptionHandle imageDesc = nil;
  62.     CGrafPtr oldPort;
  63.     GDHandle oldGDeviceH;
  64.     OSErr err = noErr;
  65.  
  66.     err = NewGWorld(&theGWorld, 16,                // pixel depth             
  67.                     trackFrame, nil, nil, (GWorldFlags)0);
  68.     CheckError(err, "\pNewGWorld");
  69.  
  70.     LockPixels(theGWorld->portPixMap);
  71.  
  72.     err = GetMaxCompressionSize(theGWorld->portPixMap, trackFrame, 0,// let ICM choose depth
  73.                                 codecNormalQuality, 'rle ', (CompressorComponent)anyCodec, &maxCompressedSize);
  74.     CheckError(err, "\pGetMaxCompressionSize");
  75.  
  76.     compressedData = NewHandle(maxCompressedSize);
  77.     CheckError(MemError(), "\pNewHandle");
  78.  
  79.     MoveHHi(compressedData);
  80.     HLock(compressedData);
  81.     compressedDataPtr = StripAddress(*compressedData);
  82.  
  83.     imageDesc = (ImageDescriptionHandle)NewHandle(4);
  84.     CheckError(MemError(), "\pNewHandle");
  85.  
  86.     GetGWorld(&oldPort, &oldGDeviceH);
  87.     SetGWorld(theGWorld, nil);
  88.  
  89.     //••••••• changed to <= 30
  90.     for (curSample = 1; curSample <= 30; curSample++)
  91.     {
  92.         EraseRect(trackFrame);
  93.         DrawFrame(trackFrame, curSample);
  94.  
  95.         err = CompressImage(theGWorld->portPixMap, trackFrame, codecNormalQuality, 'rle ', imageDesc, compressedDataPtr);
  96.         CheckError(err, "\pCompressImage");
  97.  
  98.         err = AddMediaSample(theMedia, compressedData, 0,// no offset in data
  99.                              (**imageDesc).dataSize, 60,// frame duration = 1/10 sec
  100.                              (SampleDescriptionHandle)imageDesc, 1,// one sample
  101.                              0,                    // self-contained samples
  102.                              nil);
  103.         CheckError(err, "\pAddMediaSample");
  104.     }
  105.  
  106.     SetGWorld(oldPort, oldGDeviceH);
  107.  
  108.     if (imageDesc)
  109.         DisposeHandle((Handle)imageDesc);
  110.     if (compressedData)
  111.         DisposeHandle(compressedData);
  112.     if (theGWorld)
  113.         DisposeGWorld(theGWorld);
  114. }
  115.  
  116. void CreateMyVideoTrack(Movie theMovie)
  117. {
  118.     Track theTrack;
  119.     Media theMedia;
  120.     OSErr err = noErr;
  121.     Rect trackFrame =
  122.     {
  123.         0,  0, 100, 320
  124.     }
  125.     ;
  126.  
  127.     theTrack = NewMovieTrack(theMovie, FixRatio(trackFrame.right, 1), FixRatio(trackFrame.bottom, 1), kNoVolume);
  128.     CheckError(GetMoviesError(), "\pNewMovieTrack");
  129.  
  130.     theMedia = NewTrackMedia(theTrack, VideoMediaType, 600,// Video Time Scale
  131.                              nil, 0);
  132.     CheckError(GetMoviesError(), "\pNewTrackMedia");
  133.  
  134.     err = BeginMediaEdits(theMedia);
  135.     CheckError(err, "\pBeginMediaEdits");
  136.  
  137.     AddVideoSamplesToMedia(theMedia, &trackFrame);
  138.  
  139.     err = EndMediaEdits(theMedia);
  140.     CheckError(err, "\pEndMediaEdits");
  141.  
  142.     err = InsertMediaIntoTrack(theTrack, 0,        // track start time
  143.                                0,                // media start time
  144.                                GetMediaDuration(theMedia), fixed1);
  145.     CheckError(err, "\pInsertMediaIntoTrack");
  146. }
  147.  
  148. void CreateMyCoolMovie(void)
  149. {
  150.     Point where =
  151.     {
  152.         100,  100
  153.     }
  154.     ;
  155.  
  156.     SFReply theSFReply;
  157.     Movie theMovie = nil;
  158.     FSSpec mySpec;
  159.     short resRefNum = 0;
  160.     short resId = 0;
  161.     OSErr err = noErr;
  162.  
  163.     SFPutFile(where, "\pEnter movie file name:", "\pMovie File", nil, &theSFReply);
  164.     if (!theSFReply.good)
  165.         return;
  166.  
  167.     FSMakeFSSpec(theSFReply.vRefNum, 0, theSFReply.fName, &mySpec);
  168.  
  169.     err = CreateMovieFile(&mySpec, 'TVOD', smCurrentScript, createMovieFileDeleteCurFile, &resRefNum, &theMovie);
  170.     CheckError(err, "\pCreateMovieFile");
  171.  
  172.     CreateMyVideoTrack(theMovie);
  173.     CreateMySoundTrack(theMovie);
  174.  
  175.     err = AddMovieResource(theMovie, resRefNum, &resId, theSFReply.fName);
  176.     CheckError(err, "\pAddMovieResource");
  177.  
  178.     if (resRefNum)
  179.         CloseMovieFile(resRefNum);
  180.     DisposeMovie(theMovie);
  181. }
  182. void InitMovieToolbox(void)
  183. {
  184.     OSErr err;
  185.  
  186.     InitGraf(&qd.thePort);
  187.     InitFonts();
  188.     InitWindows();
  189.     InitMenus();
  190.     TEInit();
  191.     InitDialogs(nil);
  192.     MaxApplZone();
  193.  
  194.     if (!IsQuickTimeInstalled())
  195.     {
  196.         CheckError(-1, "\pPlease install QuickTime and try again.");
  197.     }
  198.  
  199.     err = EnterMovies();
  200.     CheckError(err, "\pEnterMovies");
  201. }
  202.  
  203.  
  204. // MAIN FUNCTION
  205. void MainCreate(void);
  206. void MainCreate(void)
  207. {
  208.     InitMovieToolbox();
  209.     CreateMyCoolMovie();
  210. }
  211. void MainPlay1(void);
  212. void MainPlay1(void)
  213. {
  214.     WindowPtr aWindow;
  215.     Rect windowRect;
  216.     Rect movieBox;
  217.     Movie aMovie;
  218.     Boolean done = false;
  219.     OSErr err;
  220.     EventRecord theEvent;
  221.     WindowPtr whichWindow;
  222.     short part;
  223.  
  224.     InitGraf(&qd.thePort);
  225.     InitFonts();
  226.     InitWindows();
  227.     InitMenus();
  228.     TEInit();
  229.     InitDialogs(nil);
  230.     MaxApplZone();
  231.  
  232.     if (!IsQuickTimeInstalled())
  233.     {
  234.         CheckError(-1, "\pPlease install QuickTime and try again.");
  235.     }
  236.  
  237.     err = EnterMovies();
  238.     if (err)
  239.         return;
  240.  
  241.     SetRect(&windowRect, 100, 100, 200, 200);
  242.     aWindow = NewCWindow(nil, &windowRect, "\pMovie", false, noGrowDocProc, (WindowPtr) - 1, true, 0);
  243.  
  244.     SetPort(aWindow);
  245.     aMovie = GetMovie();
  246.     if (aMovie == nil)
  247.         return;
  248.  
  249.     GetMovieBox(aMovie, &movieBox);
  250.     OffsetRect(&movieBox, -movieBox.left, -movieBox.top);
  251.     SetMovieBox(aMovie, &movieBox);
  252.  
  253.     SizeWindow(aWindow, movieBox.right, movieBox.bottom, true);
  254.     ShowWindow(aWindow);
  255.  
  256.     SetMovieGWorld(aMovie, (CGrafPtr)aWindow, nil);
  257.  
  258.     StartMovie(aMovie);
  259.  
  260.     while (!IsMovieDone(aMovie) &&!done)
  261.     {
  262.         if (WaitNextEvent(everyEvent, &theEvent, 0, nil))
  263.         {
  264.             switch (theEvent.what)
  265.             {
  266.                 case updateEvt:
  267.                     whichWindow = (WindowPtr)theEvent.message;
  268.                     if (whichWindow == aWindow)
  269.                     {
  270.                         BeginUpdate(whichWindow);
  271.                         UpdateMovie(aMovie);
  272.                         SetPort(whichWindow);
  273.                         EraseRect(&whichWindow->portRect);
  274.                         EndUpdate(whichWindow);
  275.                     }
  276.                     break;
  277.  
  278.                 case mouseDown:
  279.                     part = FindWindow(theEvent.where, &whichWindow);
  280.                     if (whichWindow == aWindow)
  281.                     {
  282.                         switch (part)
  283.                         {
  284.                             case inGoAway:
  285.                                 done = TrackGoAway(whichWindow, theEvent.where);
  286.                                 break;
  287.                             case inDrag:
  288.                                 DragWindow(whichWindow, theEvent.where, &qd.screenBits.bounds);
  289.                                 break;
  290.                         }
  291.                     }
  292.                     break;
  293.             }
  294.         }
  295.         MoviesTask(aMovie, DoTheRightThing);
  296.     }
  297.     DisposeMovie(aMovie);
  298.     DisposeWindow(aWindow);
  299. }
  300. void MainPlay2(void);
  301. void MainPlay2(void)
  302. {
  303.     MovieController aController;
  304.     WindowPtr aWindow;
  305.     Rect aRect;
  306.     Movie aMovie;
  307.     Boolean done = false;
  308.     OSErr err;
  309.     EventRecord theEvent;
  310.     WindowPtr whichWindow;
  311.     short part;
  312.  
  313.     InitGraf(&qd.thePort);
  314.     InitFonts();
  315.     InitWindows();
  316.     InitMenus();
  317.     TEInit();
  318.     InitDialogs(nil);
  319.     MaxApplZone();
  320.  
  321.     if (!IsQuickTimeInstalled())
  322.     {
  323.         CheckError(-1, "\pPlease install QuickTime and try again.");
  324.     }
  325.  
  326.     err = EnterMovies();
  327.     if (err)
  328.         return;
  329.  
  330.     SetRect(&aRect, 100, 100, 200, 200);
  331.     aWindow = NewCWindow(nil, &aRect, "\pMovie", false, noGrowDocProc, (WindowPtr) - 1, true, 0);
  332.     SetPort(aWindow);
  333.     aMovie = GetMovie();
  334.     if (aMovie == nil)
  335.         return;
  336.  
  337.     SetRect(&aRect, 0, 0, 100, 100);
  338.     aController = NewMovieController(aMovie, &aRect, mcTopLeftMovie);
  339.     if (aController == nil)
  340.         return;
  341.  
  342.     err = MCGetControllerBoundsRect(aController, &aRect);
  343.     SizeWindow(aWindow, aRect.right, aRect.bottom, true);
  344.     ShowWindow(aWindow);
  345.     err = MCDoAction(aController, mcActionSetKeysEnabled, (Ptr)true);
  346.  
  347.     while (!done)
  348.     {
  349.         WaitNextEvent(everyEvent, &theEvent, 0, nil);
  350.         if (!MCIsPlayerEvent(aController, &theEvent))
  351.         {
  352.             switch (theEvent.what)
  353.             {
  354.                 case updateEvt:
  355.                     whichWindow = (WindowPtr)theEvent.message;
  356.                     BeginUpdate(whichWindow);
  357.                     EraseRect(&whichWindow->portRect);
  358.                     EndUpdate(whichWindow);
  359.                     break;
  360.                 case mouseDown:
  361.                     part = FindWindow(theEvent.where, &whichWindow);
  362.                     if (whichWindow == aWindow)
  363.                     {
  364.                         switch (part)
  365.                         {
  366.                             case inGoAway:
  367.                                 done = TrackGoAway(whichWindow, theEvent.where);
  368.                                 break;
  369.  
  370.                             case inDrag:
  371.                                 DragWindow(whichWindow, theEvent.where, &qd.screenBits.bounds);
  372.                                 break;
  373.                         }
  374.                     }
  375.             }
  376.         }
  377.     }
  378.     DisposeMovieController(aController);
  379.     DisposeMovie(aMovie);
  380.     DisposeWindow(aWindow);
  381. }
  382. Movie GetMovie(void)
  383. {
  384.     OSErr err;
  385.     SFTypeList typeList =
  386.     {
  387.         MovieFileType,  0, 0, 0
  388.     };
  389.     StandardFileReply reply;
  390.     Movie aMovie = nil;
  391.     short movieResFile;
  392.  
  393.     StandardGetFilePreview(nil, 1, typeList, &reply);
  394.     if (reply.sfGood)
  395.     {
  396.         err = OpenMovieFile(&reply.sfFile, &movieResFile, fsRdPerm);
  397.         if (err == noErr)
  398.         {
  399.             short movieResID = 0;                // want first movie
  400.             Str255 movieName;
  401.             Boolean wasChanged;
  402.  
  403.             err = NewMovieFromFile(&aMovie, movieResFile, &movieResID, movieName, newMovieActive,// flags
  404.                                    &wasChanged);
  405.             CloseMovieFile(movieResFile);
  406.         }
  407.     }
  408.     return aMovie;
  409. }
  410.  
  411.  
  412. void CreateTrackMatte(Track theTrack)
  413. {
  414.     QDErr err;
  415.     GWorldPtr aGW;
  416.     Rect trackBox;
  417.     Fixed trackHeight;
  418.     Fixed trackWidth;
  419.     CTabHandle grayCTab;
  420.  
  421.     GetTrackDimensions(theTrack, &trackWidth, &trackHeight);
  422.     SetRect(&trackBox, 0, 0, FixRound(trackWidth), FixRound(trackHeight));
  423.  
  424.     grayCTab = GetCTable(40);                    // 8 bit + 32 = 8 bit gray 
  425.     err = NewGWorld(&aGW, 8, &trackBox, grayCTab, (GDHandle)nil, 0);
  426.     DisposeCTable(grayCTab);
  427.     if (!err && (aGW != nil))
  428.     {
  429.         SetTrackMatte(theTrack, aGW->portPixMap);
  430.         DisposeGWorld(aGW);
  431.     }
  432. }
  433.  
  434.  
  435. void UpdateTrackMatte(Track theTrack)
  436. {
  437.     OSErr err;
  438.     PixMapHandle trackMatte;
  439.     PixMapHandle savePortPix;
  440.     Movie theMovie;
  441.     GWorldPtr tempGW;
  442.     CGrafPtr savePort;
  443.     GDHandle saveGDevice;
  444.     Rect matteBox;
  445.     short i;
  446.  
  447.     theMovie = GetTrackMovie(theTrack);
  448.     trackMatte = GetTrackMatte(theTrack);
  449.     if (trackMatte == nil)
  450.     {
  451.         // track doesn't have a matte, so give it one
  452.         CreateTrackMatte(theTrack);
  453.         trackMatte = GetTrackMatte(theTrack);
  454.         if (trackMatte == nil)
  455.             return;
  456.     }
  457.  
  458.     GetGWorld(&savePort, &saveGDevice);
  459.     matteBox = (**trackMatte).bounds;
  460.     err = NewGWorld(&tempGW, (**trackMatte).pixelSize, &matteBox, (**trackMatte).pmTable, (GDHandle)nil, 0);
  461.     if (err || (tempGW == nil))
  462.         return;
  463.  
  464.     SetGWorld(tempGW, nil);
  465.     savePortPix = tempGW->portPixMap;
  466.     LockPixels(trackMatte);
  467.     SetPortPix(trackMatte);
  468.  
  469.     // draw a gray ramp rectangle around the edge of the matte     
  470.     for (i = 0; i < 35; i++)
  471.     {
  472.         RGBColor aColor;
  473.         long tempLong;
  474.  
  475.         tempLong = 65536 - ((65536 / 35) * (long)i);
  476.         aColor.red = aColor.green = aColor.blue = tempLong;
  477.         RGBForeColor(&aColor);
  478.         FrameRect(&matteBox);
  479.         InsetRect(&matteBox, 1, 1);
  480.     }
  481.  
  482.     // fill the center of the matte with black
  483.     ForeColor(blackColor);
  484.     PaintRect(&matteBox);
  485.  
  486.     SetPortPix(savePortPix);
  487.     SetGWorld(savePort, saveGDevice);
  488.     DisposeGWorld(tempGW);
  489.  
  490.     UnlockPixels(trackMatte);
  491.     SetTrackMatte(theTrack, trackMatte);
  492.  
  493.     DisposeMatte(trackMatte);
  494. }
  495.  
  496.  
  497. pascal OSErr MyCoverProc(Movie aMovie,
  498.                          RgnHandle changedRgn,
  499.                          long refcon)
  500. {
  501.     #pragma unused(refcon)
  502.     CGrafPtr mPort;
  503.     GDHandle mGD;
  504.  
  505.     GetMovieGWorld(aMovie, &mPort, &mGD);
  506.     DiffRgn(mPort->clipRgn, changedRgn, mPort->clipRgn);
  507.     return noErr;
  508. }
  509.  
  510.  
  511. pascal OSErr MyUnCoverProc(Movie aMovie,
  512.                            RgnHandle changedRgn,
  513.                            long refcon)
  514. {
  515.     #pragma unused(refcon)
  516.     CGrafPtr mPort,  curPort;
  517.     GDHandle mGD,  curGD;
  518.  
  519.     GetMovieGWorld(aMovie, &mPort, &mGD);
  520.     GetGWorld(&curPort, &curGD);
  521.     SetGWorld(mPort, mGD);
  522.  
  523.     InvalRgn(changedRgn);
  524.     UnionRgn(mPort->clipRgn, changedRgn, mPort->clipRgn);
  525.  
  526.     SetGWorld(curPort, curGD);
  527.     return noErr;
  528. }
  529.  
  530.  
  531.     void InitCoverProcs(WindowPtr aWindow,
  532.                         Movie aMovie)
  533.     {
  534.         RgnHandle displayBounds;
  535.         GrafPtr curPort;
  536.  
  537.         displayBounds = GetMovieDisplayBoundsRgn(aMovie);
  538.         if (displayBounds == nil)
  539.             return;
  540.  
  541.         GetPort(&curPort);
  542.         SetPort(aWindow);
  543.         ClipRect(&aWindow->portRect);
  544.         DiffRgn(aWindow->clipRgn, displayBounds, aWindow->clipRgn);
  545.         DisposeRgn(displayBounds);
  546.         SetPort(curPort);
  547.  
  548.         SetMovieCoverProcs(aMovie, NewMovieRgnCoverProc(MyUnCoverProc), NewMovieRgnCoverProc(MyCoverProc), 0);
  549.     }
  550.  
  551.  
  552. void DoUpdate(WindowPtr theWindow,
  553.               Movie theMovie)
  554. {
  555.     BeginUpdate(theWindow);
  556.     UpdateMovie(theMovie);
  557.     EndUpdate(theWindow);
  558. }
  559.  
  560. #pragma options align=mac68k
  561. typedef SndCommand* SndCmdPtr;
  562.  
  563. typedef struct
  564. {
  565.     short format;
  566.     short numSynths;
  567. } Snd1Header, * Snd1HdrPtr, ** Snd1HdrHndl;
  568.  
  569. typedef struct
  570. {
  571.     short format;
  572.     short refCount;
  573. } Snd2Header, * Snd2HdrPtr, ** Snd2HdrHndl;
  574.  
  575. typedef struct
  576. {
  577.     short synthID;
  578.     long initOption;
  579. } SynthInfo, * SynthInfoPtr;
  580. #pragma options align=reset
  581.  
  582. // FUNCTIONS
  583. long GetSndHdrOffset(Handle sndHandle)
  584. {
  585.     short howManyCmds;
  586.     long sndOffset = 0;
  587.     Ptr sndPtr;
  588.  
  589.     if (sndHandle == nil)
  590.         return 0;
  591.     sndPtr = *sndHandle;
  592.     if (sndPtr == nil)
  593.         return 0;
  594.  
  595.     if ((*(Snd1HdrPtr)sndPtr).format == firstSoundFormat)
  596.     {
  597.         short synths = ((Snd1HdrPtr)sndPtr)->numSynths;
  598.         sndPtr += sizeof(Snd1Header) + (sizeof(SynthInfo) * synths);
  599.     }
  600.     else
  601.     {
  602.         sndPtr += sizeof(Snd2Header);
  603.     }
  604.  
  605.     howManyCmds = *(short*)sndPtr;
  606.  
  607.     sndPtr += sizeof(howManyCmds);
  608.     // sndPtr is now at the first sound command - cruise all
  609.     //         commands and find the first soundCmd or bufferCmd
  610.     while (howManyCmds > 0)
  611.     {
  612.         switch (((SndCmdPtr)sndPtr)->cmd)
  613.         {
  614.             case (soundCmd + dataOffsetFlag):
  615.             case (bufferCmd + dataOffsetFlag):
  616.                 sndOffset = ((SndCmdPtr)sndPtr)->param2;
  617.                 howManyCmds = 0;                /* done, get out of loop */
  618.                 break;
  619.             default:                            /* catch any other type of commands */
  620.                 sndPtr += sizeof(SndCommand);
  621.                 howManyCmds--;
  622.                 break;
  623.         }
  624.     }                                            /* done with all the commands */
  625.  
  626.     return sndOffset;
  627. }
  628.  
  629.  
  630. #define kMACEBeginningNumberOfBytes  6
  631. #define kMACE31MonoPacketSize  2
  632. #define kMACE31StereoPacketSize  4
  633. #define kMACE61MonoPacketSize  1
  634. #define kMACE61StereoPacketSize  2
  635.  
  636.  
  637. // FUNCTIONS
  638. void CreateSoundDescription(Handle sndHandle,
  639.                             SoundDescriptionHandle sndDesc,
  640.                             long* sndDataOffset,
  641.                             long* numSamples,
  642.                             long* sndDataSize)
  643. {
  644.     long sndHdrOffset = 0;
  645.     long sampleDataOffset;
  646.     SoundHeaderPtr sndHdrPtr = nil;
  647.     long numFrames;
  648.     long samplesPerFrame;
  649.     long bytesPerFrame;
  650.     SoundDescriptionPtr sndDescPtr;
  651.  
  652.     *sndDataOffset = 0;
  653.     *numSamples = 0;
  654.     *sndDataSize = 0;
  655.  
  656.     SetHandleSize((Handle)sndDesc, sizeof(SoundDescription));
  657.     CheckError(MemError(), "\pSetHandleSize");
  658.  
  659.     sndHdrOffset = GetSndHdrOffset(sndHandle);
  660.     if (sndHdrOffset == 0)
  661.         CheckError(-1, "\pGetSndHdrOffset ");
  662.  
  663.     // we can use pointers since we don't move memory
  664.     sndHdrPtr = (SoundHeaderPtr)(*sndHandle + sndHdrOffset);
  665.     sndDescPtr = *sndDesc;
  666.  
  667.     sndDescPtr->descSize = sizeof(SoundDescription);
  668.     // total size of sound description structure
  669.     sndDescPtr->resvd1 = 0;
  670.     sndDescPtr->resvd2 = 0;
  671.     sndDescPtr->dataRefIndex = 1;
  672.     sndDescPtr->compressionID = 0;
  673.     sndDescPtr->packetSize = 0;
  674.     sndDescPtr->version = 0;
  675.     sndDescPtr->revlevel = 0;
  676.     sndDescPtr->vendor = 0;
  677.  
  678.     switch (sndHdrPtr->encode)
  679.     {
  680.         case stdSH:
  681.             sndDescPtr->dataFormat = 'raw ';
  682.             // uncompressed offset-binary data
  683.             sndDescPtr->numChannels = 1;
  684.             // number of channels of sound
  685.             sndDescPtr->sampleSize = 8;
  686.             // number of bits per sample
  687.             sndDescPtr->sampleRate = sndHdrPtr->sampleRate;
  688.             // sample rate        
  689.             *numSamples = sndHdrPtr->length;
  690.             *sndDataSize = *numSamples;
  691.             bytesPerFrame = 1;
  692.             samplesPerFrame = 1;
  693.             sampleDataOffset = (Ptr) & sndHdrPtr->sampleArea - (Ptr)sndHdrPtr;
  694.             break;
  695.  
  696.         case extSH:
  697.             {
  698.                 ExtSoundHeaderPtr extSndHdrP;
  699.  
  700.                 extSndHdrP = (ExtSoundHeaderPtr)sndHdrPtr;
  701.  
  702.                 sndDescPtr->dataFormat = 'raw ';
  703.                 // uncompressed offset-binary data
  704.                 sndDescPtr->numChannels = extSndHdrP->numChannels;
  705.                 // number of channels of sound
  706.                 sndDescPtr->sampleSize = extSndHdrP->sampleSize;
  707.                 // number of bits per sample
  708.                 sndDescPtr->sampleRate = extSndHdrP->sampleRate;
  709.                 // sample rate            
  710.                 numFrames = extSndHdrP->numFrames;
  711.                 *numSamples = numFrames;
  712.                 bytesPerFrame = extSndHdrP->numChannels * (extSndHdrP->sampleSize / 8);
  713.                 samplesPerFrame = 1;
  714.                 *sndDataSize = numFrames * bytesPerFrame;
  715.                 sampleDataOffset = (Ptr)(&extSndHdrP->sampleArea) - (Ptr)extSndHdrP;
  716.             }
  717.             break;
  718.  
  719.         case cmpSH:
  720.             {
  721.                 CmpSoundHeaderPtr cmpSndHdrP;
  722.  
  723.                 cmpSndHdrP = (CmpSoundHeaderPtr)sndHdrPtr;
  724.                 sndDescPtr->numChannels = cmpSndHdrP->numChannels;
  725.                 // number of channels of sound
  726.                 sndDescPtr->sampleSize = cmpSndHdrP->sampleSize;
  727.                 // number of bits per sample before compression
  728.                 sndDescPtr->sampleRate = cmpSndHdrP->sampleRate;
  729.                 // sample rate
  730.                 numFrames = cmpSndHdrP->numFrames;
  731.                 sampleDataOffset = (Ptr)(&cmpSndHdrP->sampleArea) - (Ptr)cmpSndHdrP;
  732.                 switch (cmpSndHdrP->compressionID)
  733.                 {
  734.                     case threeToOne:
  735.                         sndDescPtr->dataFormat = 'MAC3';
  736.                         // compressed 3:1 data
  737.                         samplesPerFrame = kMACEBeginningNumberOfBytes;
  738.                         *numSamples = numFrames * samplesPerFrame;
  739.                         switch (cmpSndHdrP->numChannels)
  740.                         {
  741.                             case 1:
  742.                                 bytesPerFrame = cmpSndHdrP->numChannels * kMACE31MonoPacketSize;
  743.                                 break;
  744.                             case 2:
  745.                                 bytesPerFrame = cmpSndHdrP->numChannels * kMACE31StereoPacketSize;
  746.                                 break;
  747.                             default:
  748.                                 CheckError(-1, "\pCorrupt sound data");
  749.                                 break;
  750.                         }
  751.                         *sndDataSize = numFrames * bytesPerFrame;
  752.                         break;
  753.                     case sixToOne:
  754.                         sndDescPtr->dataFormat = 'MAC6';
  755.                         // compressed 6:1 data
  756.                         samplesPerFrame = kMACEBeginningNumberOfBytes;
  757.                         *numSamples = numFrames * samplesPerFrame;
  758.                         switch (cmpSndHdrP->numChannels)
  759.                         {
  760.                             case 1:
  761.                                 bytesPerFrame = cmpSndHdrP->numChannels * kMACE61MonoPacketSize;
  762.                                 break;
  763.                             case 2:
  764.                                 bytesPerFrame = cmpSndHdrP->numChannels * kMACE61StereoPacketSize;
  765.                                 break;
  766.                             default:
  767.                                 CheckError(-1, "\pCorrupt sound data");
  768.                                 break;
  769.                         }
  770.                         *sndDataSize = (*numSamples) * bytesPerFrame;
  771.                         break;
  772.                     default:
  773.                         CheckError(-1, "\pCorrupt sound data");
  774.                         break;
  775.                 }
  776.             }                                    // switch cmpSndHdrP->compressionID:*/
  777.             break;                                // of cmpSH:
  778.  
  779.         default:
  780.             CheckError(-1, "\pCorrupt sound data");
  781.             break;
  782.  
  783.     }                                            // switch sndHdrPtr->encode*/
  784.     *sndDataOffset = sndHdrOffset + sampleDataOffset;
  785. }
  786.  
  787.  
  788. void CreateMySoundTrack(Movie theMovie)
  789. {
  790.     Track theTrack;
  791.     Media theMedia;
  792.     Handle sndHandle = nil;
  793.     SoundDescriptionHandle sndDesc = nil;
  794.     long sndDataOffset;
  795.     long sndDataSize;
  796.     long numSamples;
  797.     OSErr err = noErr;
  798.  
  799.  
  800.     sndHandle = GetResource('snd ', 128);
  801.     CheckError(ResError(), "\pGetResource");
  802.     if (sndHandle == nil)
  803.         return;
  804.  
  805.     sndDesc = (SoundDescriptionHandle)NewHandle(4);
  806.     CheckError(MemError(), "\pNewHandle");
  807.  
  808.     CreateSoundDescription(sndHandle, sndDesc, &sndDataOffset, &numSamples, &sndDataSize);
  809.  
  810.     theTrack = NewMovieTrack(theMovie, 0, 0, kFullVolume);
  811.     CheckError(GetMoviesError(), "\pNewMovieTrack");
  812.  
  813.     theMedia = NewTrackMedia(theTrack, SoundMediaType, FixRound((**sndDesc).sampleRate), nil, 0);
  814.     CheckError(GetMoviesError(), "\pNewTrackMedia");
  815.  
  816.     err = BeginMediaEdits(theMedia);
  817.     CheckError(err, "\pBeginMediaEdits");
  818.  
  819.     err = AddMediaSample(theMedia, sndHandle, sndDataOffset,// offset in data
  820.                          sndDataSize, 1,        // duration of each sound sample
  821.                          (SampleDescriptionHandle)sndDesc, numSamples, 0,// self-contained samples
  822.                          nil);
  823.     CheckError(err, "\pAddMediaSample");
  824.  
  825.     err = EndMediaEdits(theMedia);
  826.     CheckError(err, "\pEndMediaEdits");
  827.  
  828.     err = InsertMediaIntoTrack(theTrack, 0,        // track start time
  829.                                0,                // media start time
  830.                                GetMediaDuration(theMedia), fixed1);
  831.     CheckError(err, "\pInsertMediaIntoTrack");
  832.  
  833.     if (sndDesc != nil)
  834.         DisposeHandle((Handle)sndDesc);
  835. }
  836.  
  837.  
  838. Boolean IsQuickTimeInstalled(void)
  839. {
  840.     short error;
  841.     long result;
  842.  
  843.     error = Gestalt(gestaltQuickTime, &result);
  844.     return (error == noErr);
  845. }
  846.  
  847.  
  848.  
  849.  
  850.  
  851.  
  852.  
  853.  
  854.  
  855.  
  856.  
  857.  
  858.  
  859.  
  860.  
  861.